package cn.wp.ewallet.wmps.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.wp.common.core.dto.WpResult;
import cn.wp.common.core.id.Id;
import cn.wp.common.core.model.WpPage;
import cn.wp.common.core.util.BeanUtil;
import cn.wp.ewallet.common.model.dto.MoneyTypeInfoDto;
import cn.wp.ewallet.common.service.MoneyTypeInfoService;
import cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant;
import cn.wp.ewallet.wallet.extension.util.EwalletWalletUtil;
import cn.wp.ewallet.wallet.model.dto.AccountInfoDto;
import cn.wp.ewallet.wallet.model.entity.AccountInfoDo;
import cn.wp.ewallet.wallet.model.entity.AccountLogDo;
import cn.wp.ewallet.wallet.model.entity.WalletInfoDo;
import cn.wp.ewallet.wallet.service.AccountInfoService;
import cn.wp.ewallet.wallet.service.AccountLogService;
import cn.wp.ewallet.wallet.service.WalletInfoService;
import cn.wp.ewallet.wmps.dao.EarnDetailLogDao;
import cn.wp.ewallet.wmps.dao.EarnStatLogDao;
import cn.wp.ewallet.wmps.dao.FinaProdInfoDao;
import cn.wp.ewallet.wmps.dao.ProdOrderRelDao;
import cn.wp.ewallet.wmps.extension.constant.EwalletWmpsConstant;
import cn.wp.ewallet.wmps.model.dto.FinaProdCountDto;
import cn.wp.ewallet.wmps.model.entity.*;
import cn.wp.ewallet.wmps.service.TtySSettlementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import static cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant.ACCOUNT_TYPE_AVAILABLE;

/**
 * Created by yangjin on 2020/1/15
 */
@Slf4j
@Service
public class TtySSettlementServiceImpl implements TtySSettlementService {

    @Autowired
    private WalletInfoService walletInfoService;

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private ProdOrderRelDao prodOrderRelDao;

    @Autowired
    private FinaProdInfoDao finaProdInfoDao;

    @Autowired
    private AccountLogService accountLogService;

    @Autowired
    private EarnDetailLogDao earnDetailLogDao;

    @Autowired
    private EarnStatLogDao earnStatLogDao;

    @Autowired
    private MoneyTypeInfoService moneyTypeInfoService;

    @Override
    public void ttyEarnSettle() {
        List<WalletInfoDo> walletInfoDos = walletInfoService.getAllByWalletType();
        for (WalletInfoDo walletInfoDo : walletInfoDos) {
            String walletAddress = walletInfoDo.getWalletAddress();
            AccountInfoDo accountInfoDo = accountInfoService.selectAccountByWalletAddAccountType(walletAddress, EwalletWmpsConstant.ACCOUNT_TYPE_DAILY);
            if (accountInfoDo == null) {
                log.info("该地址的" + walletAddress + "天天盈账户不存在");
                continue;
            }

            String accountId = accountInfoDo.getAccountId();
            //根据账户ID查询待计息订购单总额
            List<ProdOrderRelDo> prodOrderRelDos = prodOrderRelDao.selectProdOrderRelListByAccountIdAndOrderStatus(accountId, EwalletWmpsConstant.ORDER_STATUS_WAITING);
            BigDecimal ineffectiveAmount = BigDecimal.valueOf(0);
            if (CollectionUtil.isNotEmpty(prodOrderRelDos)) {
                for (ProdOrderRelDo prodOrderRelDo : prodOrderRelDos) {
                    if (prodOrderRelDo.getPurchAmount() != null) {
                        ineffectiveAmount = ineffectiveAmount.add(prodOrderRelDo.getPurchAmount());
                    }
                }
            }
            //根据账户id查询天天盈账户总额
            AccountInfoDo accountInfoDoByAccountId = accountInfoService.getAccountInfoDoByAccountId(accountId);
            BigDecimal moneyAmount = accountInfoDoByAccountId.getMoneyAmount();
            //生效中的天天盈金额 (天天盈总额-未生效（待计息）的金额)
            BigDecimal amount = moneyAmount.subtract(ineffectiveAmount);
            //天天盈账户余额小于待计息数量，不计算，直接返回
            if (amount.compareTo(BigDecimal.ZERO) < 1) {
                continue;
            }
            //天天盈理财明细，需要任意一个计息中的订单ID，否则APP查询收益明细时无法关联数据
            List<ProdOrderRelDo> pList = prodOrderRelDao.selectProdOrderRelListByAccountIdAndOrderStatus(accountId, EwalletWmpsConstant.ORDER_STATUS_END);
            if (CollectionUtil.isEmpty(pList)) {
                log.info("无计息中订单， 地址={}", walletAddress);
                continue;
            }

            List<FinaProdInfoDo> list = finaProdInfoDao.selectFinaProdInfoByProcType(EwalletWmpsConstant.PROD_TYPE_DAILY);
            if (CollectionUtil.isNotEmpty(list)) {
                //年化收益率
                BigDecimal yieldRate = list.get(0).getYieldRate();
                //执行天天盈日结
                excute(walletAddress, amount, yieldRate, pList.get(0).getProdOrderId());
                log.info("天天盈返息成功， 地址={}", walletAddress);
            }else {
                log.error("数据错误，天天盈理财产品查询失败，地址={}", walletAddress);
            }

        }
    }

    /**
     * 执行天天盈日结
     * @param walletAddress
     * @param amount
     * @param yieldRate
     */
    @Transactional
    protected void excute(String walletAddress, BigDecimal amount, BigDecimal yieldRate, String prodOrderId){

        //获取该年总天数
        int daysOfThisYear = getDaysOfThisYear();
        //每日收益
        BigDecimal dailyEarn = amount.multiply(yieldRate).divide(BigDecimal.valueOf(daysOfThisYear), 8, BigDecimal.ROUND_HALF_UP);
        //更新可用账户并保存资产变动信息
        accountInfoService.saveAccountChange(walletAddress, dailyEarn, EwalletWalletConstant.ACCOUNT_ADD, EwalletWalletConstant.ACCOUNT_CHARGE_CASE_FINANCIAL_INCOME, EwalletWalletConstant.MONEY_TYPE_SHQC, ACCOUNT_TYPE_AVAILABLE);

        //收益明细记录
        AccountInfoDto accountInfoDto = accountInfoService.selectAccountByWalletAddMoneyTypeId(walletAddress, EwalletWalletConstant.MONEY_TYPE_SHQC, ACCOUNT_TYPE_AVAILABLE);
        saveEarnDetailLog(accountInfoDto.getAccountId(), dailyEarn, prodOrderId);

        //记录收益统计
        EarnStatLogDo todayEarnStatLogDo = earnStatLogDao.selectEarnLogByStatDateAndWalletAddress(Date.from(LocalDate.now().minusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()), walletAddress);
        EarnStatLogDo yesterdayEarnStatLogDo = earnStatLogDao.selectEarnLogByStatDateAndWalletAddress(Date.from(LocalDate.now().minusDays(2).atStartOfDay(ZoneId.systemDefault()).toInstant()), walletAddress);
        if (null != yesterdayEarnStatLogDo) {
            if (null != todayEarnStatLogDo) {
                todayEarnStatLogDo.setTtyTotalEarn(dailyEarn.add(yesterdayEarnStatLogDo.getTtyTotalEarn()));
                todayEarnStatLogDo.setTotalEarn(dailyEarn.add(yesterdayEarnStatLogDo.getTotalEarn()));
                earnStatLogDao.update(todayEarnStatLogDo);
            } else {
                EarnStatLogDo earnStatLogDo = new EarnStatLogDo();
                earnStatLogDo.setStatDate(DateUtil.offsetDay(new Date(), -1));
                earnStatLogDo.setTtyTotalEarn(dailyEarn.add(yesterdayEarnStatLogDo.getTtyTotalEarn()));
                earnStatLogDo.setTotalEarn(dailyEarn.add(yesterdayEarnStatLogDo.getTotalEarn()));
                earnStatLogDo.setReturnEarn(BigDecimal.valueOf(0));
                earnStatLogDo.setFinaTotalEarn(BigDecimal.valueOf(0));
                earnStatLogDo.setWalletAddress(walletAddress);
                earnStatLogDao.insert(earnStatLogDo);
            }
        } else {
            if (null != todayEarnStatLogDo) {
                todayEarnStatLogDo.setTtyTotalEarn(dailyEarn);
                todayEarnStatLogDo.setTotalEarn(todayEarnStatLogDo.getTotalEarn().add(dailyEarn));
                earnStatLogDao.update(todayEarnStatLogDo);
            } else {
                EarnStatLogDo earnStatLogDo = new EarnStatLogDo();
                earnStatLogDo.setStatDate(DateUtil.offsetDay(new Date(), -1));
                earnStatLogDo.setTtyTotalEarn(dailyEarn);
                earnStatLogDo.setTotalEarn(dailyEarn);
                earnStatLogDo.setReturnEarn(BigDecimal.valueOf(0));
                earnStatLogDo.setFinaTotalEarn(BigDecimal.valueOf(0));
                earnStatLogDo.setWalletAddress(walletAddress);
                earnStatLogDao.insert(earnStatLogDo);
            }
        }
    }

    /**
     * 查询你理财产品的概览情况
     *
     * @return
     */
    @Override
    public WpResult getTtyCountInfo() {
        FinaProdInfoDo finaProdInfoDo = finaProdInfoDao.selectTtyParams();
//       天天盈的理财产品id
        String finaProdId = finaProdInfoDo.getFinaProdId();
        WpPage<FinaProdCountDoo> finaProdCountDoo = finaProdInfoDao.getFinaProdCountDoos(finaProdId, null);
        FinaProdCountDto finaProdCountDto = BeanUtil.copyProperties(finaProdCountDoo.getList().get(0), FinaProdCountDto.class);
        finaProdCountDto.setFinaProdId(finaProdId);
        MoneyTypeInfoDto moneyTypeInfoDto = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(EwalletWalletConstant.MONEY_TYPE_SHQC);
        BigDecimal source = finaProdCountDto.getFinaProdCountMoney();
        if (null == source) {
            finaProdCountDto.setFinaProdCountMoney(BigDecimal.ZERO);
        } else {
            finaProdCountDto.setFinaProdCountMoney(EwalletWalletUtil.toUpperWei(finaProdCountDto.getFinaProdCountMoney(), new BigDecimal(moneyTypeInfoDto.getMoneyTypeUnit())));
        }
        return new WpResult().success(finaProdCountDto);
    }

    /**
     * 获取该年总天数
     *
     * @return
     */
    private int getDaysOfThisYear() {
        //判断该年份是否为闰年  闰年--true; 平年--false
        GregorianCalendar gregorianCalendar = new GregorianCalendar();
        boolean isLeapYear = gregorianCalendar.isLeapYear(DateUtil.thisYear());
        int daysOfThisYear = 0;
        if (isLeapYear) {
            daysOfThisYear = 366;
        } else {
            daysOfThisYear = 365;
        }
        return daysOfThisYear;
    }

    private void saveEarnDetailLog(String accountId, BigDecimal dailyEarn, String prodOrderId) {
        EarnDetailLogDo earnDetailLogDo = new EarnDetailLogDo();
        earnDetailLogDo.setEarnDetailLogId(Id.gen());
        earnDetailLogDo.setDailyEarn(dailyEarn);
        earnDetailLogDo.setEarnDate(DateUtil.offsetDay(new Date(), -1));
        earnDetailLogDo.setAccountId(accountId);
        earnDetailLogDo.setEarnStatus(EwalletWmpsConstant.RETURN_STATUS_ALREADY);
        earnDetailLogDo.setCreateTime(DateUtil.date());
        earnDetailLogDo.setProdOrderId(prodOrderId);
        earnDetailLogDao.insert(earnDetailLogDo);
    }

}
